library NOTDAWorldPhysics initializer init requires TextSystem, GlobalVariables

	globals
		private trigger Ailemnts_Trigger
		private trigger LandingAreaWind
		private trigger ItemRemovalTrigger
		private group G = CreateGroup()
		
		
		boolean   udg_Lighting               = false
	endglobals
	
	
	private function PerserveInvisibleCB takes nothing returns nothing
		local timer t = GetExpiredTimer()
		local unit u = getUnit(t, "u")
		if GetUnitAbilityLevel(u, 'Agho' ) > 0 then
			call UnitRemoveAbility(u, 'Agho')
		endif
		call ReleaseTimer(t)
		set u = null
		set t = null
	endfunction
	
	function PerserveInvisibleOnSpellAction takes unit u returns nothing
		local timer t 
		if GetUnitAbilityLevel(u, 'Agho' ) == 0 then
			set t = NewTimer()
			call UnitAddAbility(u, 'Agho')
			call putUnit(t, "u", u)
			call TimerStart(t, 0.01, false, function PerserveInvisibleCB)
		endif
		set t = null
	endfunction
	
	function PerserveInvisibleOnSpellActionEX takes unit u, real timeout returns nothing
		local timer t 
		if GetUnitAbilityLevel(u, 'Agho' ) == 0 then
			set t = NewTimer()
			call UnitAddAbility(u, 'Agho')
			call putUnit(t, "u", u)
			call TimerStart(t, timeout, false, function PerserveInvisibleCB)
		endif
		set t = null
	endfunction
	
	//! textmacro create_recycle_stack takes N, ID
		globals
			private unit array dummies_$ID$
			private integer dummies_length_$ID$ = 0
		endglobals
		
		private function Get$N$ takes nothing returns unit
			local unit u
			if dummies_length_$ID$ <= 0 then 
				set u = CreateUnit(Player(12), '$ID$' ,0, 0, 0.0)
			else
				set u = dummies_$ID$[dummies_length_$ID$]
				set dummies_length_$ID$ = dummies_length_$ID$ - 1
			endif

			call PauseUnit(u, false)
			call ShowUnit(u, true)
			call SetUnitPathing(u, false)
			set dummies_$ID$[0] = u
			set u = null
			return dummies_$ID$[0]
		endfunction
		
		private function Remove$N$ takes unit u returns nothing	
			set dummies_length_$ID$  = dummies_length_$ID$  + 1
			set dummies_$ID$[dummies_length_$ID$ ] = u
			call SetUnitScale(u, 100.0 * 0.01, 100.0 * 0.01, 100.0 * 0.01)
			call PauseUnit(u,true)
			call ShowUnit(u, false)
		endfunction
	//! endtextmacro

	// danger zone dummy
	//! runtextmacro create_recycle_stack("DummyUnit1", "n00P") 

	private function GernadeStunAOE_p takes real x, real y returns nothing
		local unit u = GetDummyUnit1()
		call SetUnitX(u, x)
		call SetUnitY(u, y)
		call UnitAddAbility(u, 'A094')
		call TriggerSleepAction(0.5)
		call UnitRemoveAbility(u, 'A094')
		call RemoveDummyUnit1(u)
		set u = null
	endfunction
	function GernadeStunAOE takes real x, real y returns nothing
		call GernadeStunAOE_p.execute(x,y)
	endfunction
	
	function CastInvisibleOn takes unit target returns nothing 
		local unit u = GetDummyUnit1()
		call SetUnitX(u, GetUnitX(target))
		call SetUnitY(u, GetUnitY(target))
		call SetUnitOwner(u, GetOwningPlayer(target), false)
		call SetUnitManaPercentBJ(u, 100.0)
		call UnitAddAbility(u, 'A01N')
		call IssueTargetOrderById(u, ORDER.invisibility, target)
		call TriggerSleepAction(1.0)
		call SetUnitManaPercentBJ(u, 100.0)
		call SetUnitOwner(u, Player(12), false)
		call UnitRemoveAbility(u, 'A01N')
		call RemoveDummyUnit1(u)
		set u = null
	endfunction

	private function ItemRemovalEngine takes nothing returns nothing
		local unit u = GetTriggerUnit()
		local integer inven = 0
		local item i
		local integer id
		if GetUnitPointValue(u)==12 then
			loop
				exitwhen inven>5
				set i = UnitItemInSlot(u,inven)
				set id = GetItemTypeId(i)
				if id=='I001' or id=='I005' or id=='I00X' or id=='I00O' or id=='I007' or id=='I003' then //Composite, Reactive, Pancor, TX-1,SAM-R, Hecate
					call RemoveItem(i)
				endif
				set inven=inven+1
			endloop
		endif
		set i = null
		set u = null
	endfunction
	
	function DisableRareItemDropsOnDeath takes player p returns nothing
		call TriggerRegisterAnyUnitEventBJ(ItemRemovalTrigger, EVENT_PLAYER_UNIT_DEATH)
	endfunction
	
	function SetLandingAreaWindEnabled takes boolean b returns nothing
		if b then 
			call EnableTrigger(LandingAreaWind)
		else
			call DisableTrigger(LandingAreaWind)
		endif
	endfunction

	function ShiftMoveSpeed takes unit u, real shift returns nothing
		local real ms
		if GetWidgetLife(u)>0.405 then
			set ms = getReal(u,"MoveSpeed")
			call putReal(u,"MoveSpeed",ms+shift)
			call SetUnitMoveSpeed( u, GetUnitDefaultMoveSpeed(u) + ms + shift )
		endif
	endfunction
	
	//===========================================================================
	// World Physics
	//===========================================================================

	function Clamp takes real r, real min, real max returns real
		if r>max then
			return max
		elseif r<min then
			return min
		else
			return r
		endif
	endfunction

	function SpawnLoc takes location l, player p, integer utype, integer n returns nothing
		local integer A=1
		loop       
			exitwhen A>n
			call TriggerSleepAction(0.)
			call CreateUnitAtLoc(p,utype,l,0.0)
			set A=A+1
		endloop
	endfunction

	function SpawnPoint takes real x, real y, player p, integer utype, integer n returns nothing
		local integer A=1
		loop
			exitwhen A>n
			call TriggerSleepAction(0.)
			call CreateUnit(p,utype,x,y,0.0)
			set A=A+1
		endloop
	endfunction

	function GankLoc takes location l, player p, integer i, integer n, real r1, real r2 returns nothing
		local integer A = 1
		local real x = GetLocationX(l)
		local real y = GetLocationY(l)
		local real r
		local real theta
		local unit u
		local real maxx = GetRectMaxX(bj_mapInitialPlayableArea)
		local real maxy = GetRectMaxY(bj_mapInitialPlayableArea)
		local real minx = GetRectMinX(bj_mapInitialPlayableArea)
		local real miny = GetRectMinY(bj_mapInitialPlayableArea)
		loop        
			exitwhen A>n
			call TriggerSleepAction(0.)
			set r = GetRandomReal(r1,r2)
			set theta = GetRandomReal(0,6.28)
			set u = CreateUnit(p,i,Clamp(x+r*Cos(theta),minx,maxx),Clamp(y+r*Sin(theta),miny,maxy),theta+3.14)
			call IssuePointOrderLoc(u,"attack",l)
			set A=A+1
		endloop
		set u = null
	endfunction

	function GankUnit takes unit victim, player p, integer gankertype, integer n, real r1, real r2 returns nothing
		local location l = GetUnitLoc(victim)
		call GankLoc(l,p,gankertype,n,r1,r2)
		call RemoveLocation(l)
		set l = null
	endfunction

	function GankMarine takes player p, integer i, integer n, real r1, real r2 returns nothing
		local integer A = 1
		local integer i2 = udg_Sorted[GetRandomInt(1,udg_Players)]
		local real x = GetUnitX(udg_Hero[i2])
		local real y = GetUnitY(udg_Hero[i2])
		local real r
		local real theta
		local unit u
		local real maxx = GetRectMaxX(bj_mapInitialPlayableArea)
		local real maxy = GetRectMaxY(bj_mapInitialPlayableArea)
		local real minx = GetRectMinX(bj_mapInitialPlayableArea)
		local real miny = GetRectMinY(bj_mapInitialPlayableArea)
		loop        
			exitwhen A>n
			call TriggerSleepAction(0.)
			set r = GetRandomReal(r1,r2)
			set theta = GetRandomReal(0,6.28)
			set u = CreateUnit(p,i,Clamp(x+r*Cos(theta),minx,maxx),Clamp(y+r*Sin(theta),miny,maxy),theta+3.14)
			call IssuePointOrder(u,"attack",x,y)
			set A=A+1
		endloop
		set u = null
	endfunction

	//Spawn n units in one bunch at a random spot in a rectangle
	function SpawnRectRandom takes rect r, player p, integer utype, integer n returns nothing
		local real x
		local real y
		local integer i = 1
		loop
			exitwhen i>n
			set x = GetRandomReal(GetRectMinX(r),GetRectMaxX(r))
			set y = GetRandomReal(GetRectMinY(r),GetRectMaxY(r))
			call TriggerSleepAction(0.)
			call CreateUnit(p,utype,x,y,0.0)
			set i=i+1
		endloop
	endfunction

	//Spawn bunches of nunits in a random undead spawn owned by udg_SpawnPlayer ntimes
	function RandomSpawn takes integer utype, integer nunits, integer ntimes returns nothing
		local integer i = 1
		local integer i2 = 1
		local integer spawn = GetRandomInt(1,4)
		local real x
		local real y
		loop
			exitwhen i>ntimes
			set x = GetRandomReal(GetRectMinX(udg_UndeadRandomSpawn[spawn]),GetRectMaxX(udg_UndeadRandomSpawn[spawn]))
			set y = GetRandomReal(GetRectMinY(udg_UndeadRandomSpawn[spawn]),GetRectMaxY(udg_UndeadRandomSpawn[spawn]))
			loop
				exitwhen i2>nunits
				call TriggerSleepAction(0.)
				call CreateUnit(udg_SpawnPlayer,utype,x,y,0.0)
				set i2=i2+1
			endloop
			set i=i+1
		endloop  
	endfunction

	function GankRectCenter takes rect r, player p, integer utype, integer n, real r1, real r2 returns nothing
		local location l = GetRectCenter(r)
		call GankLoc(l,p,utype,n,r1,r2)
		call RemoveLocation(l)
		set l = null
	endfunction

	function SpawnShredder takes nothing returns nothing
		local boolean b = getBoolean(null,"UAVPresent") 

		if (b == true) then
			call RandomSpawn('u00N',2,GetRandomInt(0,2)) 
		endif

	endfunction

	function ZuluSpawnPoint takes nothing returns location
		local real x
		local real y
		local real dx
		local real dy
		loop
			set x = GetRandomReal(GetRectMinX(udg_PlayerSpawnBoundary),GetRectMaxX(udg_PlayerSpawnBoundary))
			set y = GetRandomReal(GetRectMinY(udg_PlayerSpawnBoundary),GetRectMaxY(udg_PlayerSpawnBoundary))
			set dx = x-GetUnitX(udg_Residence41)
			set dy = y-GetUnitY(udg_Residence41)
			exitwhen dx*dx+dy*dy>6250000.0 //2500 radius away from Ravenholm
		endloop
		return Location(x,y)
	endfunction


	function killexplosive takes nothing returns nothing
		local integer i = GetUnitTypeId(GetEnumUnit())
		if i=='n007' or i=='n008' then
			call SetWidgetLife(GetEnumUnit(),0.0)
		endif
	endfunction

	function killexplosiveFast takes nothing returns boolean
		local integer i = GetUnitTypeId(GetFilterUnit())
		if i=='n007' or i=='n008' then
			call SetWidgetLife(GetFilterUnit(),0.0)
		endif
		return false
	endfunction
	
	function killtree takes nothing returns nothing
		local destructable d = GetEnumDestructable()
		call SetWidgetLife( d , GetWidgetLife(d) - getInteger(null,"kill_tree_damage"))
		set d = null
	endfunction

	globals
		private real KILL_TREE_DAMAGE
	endglobals
	private function killtreeFast takes nothing returns boolean
		call SetWidgetLife( GetFilterDestructable() , GetWidgetLife(GetFilterDestructable()) - KILL_TREE_DAMAGE)
		return false
	endfunction
	
	function DamageTrees takes rect r, integer damage returns nothing
		set KILL_TREE_DAMAGE = I2R(damage)
		call EnumDestructablesInRect( r, Condition(function killtreeFast), null)
	endfunction

	function killitem takes nothing returns nothing
		call SetWidgetLife(GetEnumItem(),0.0)
	endfunction

	private function killItemFast takes nothing returns boolean
		call SetWidgetLife(GetFilterItem(),0.0)
		return false
	endfunction
	
	function SetNoise takes real magnitude returns nothing

	endfunction

	function ClearNoise takes nothing returns nothing

	endfunction

	function TreeShake takes nothing returns nothing
		local destructable d = GetEnumDestructable()
		if GetDestructableLife(d)>0.405 then
			call SetDestructableAnimationSpeed(d,0.35)
			call SetDestructableAnimation(d,"stand - hit")
		endif
		set d = null
	endfunction

	function TreeShakeEnd takes nothing returns nothing
		local destructable d = GetEnumDestructable()
		if GetDestructableLife(d)>0.405 then
			call SetDestructableAnimationSpeed(d,1.0)
			call SetDestructableAnimation(d,"stand")
		endif
		set d = null
	endfunction

	function DamageArea takes unit caster, location target,integer damage, integer radius returns nothing
	   call UnitDamagePoint( caster,0,radius,GetLocationX(target),GetLocationY(target),damage,true,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_DEMOLITION,WEAPON_TYPE_WHOKNOWS )
	endfunction

	function DamageAreaExplosion takes unit caster, real x, real y,integer damage, real radius returns nothing
	   call UnitDamagePoint( caster,0,radius,x,y,damage,true,false,ATTACK_TYPE_SIEGE,DAMAGE_TYPE_DEMOLITION,WEAPON_TYPE_WHOKNOWS )
	endfunction

	function DamageAreaExplosionBJ takes unit caster, location target,integer damage, real radius returns nothing
	   call DamageAreaExplosion (caster,GetLocationX(target),GetLocationY(target),damage,radius )
	endfunction

	// returns if line from origin to target is blocked by a cliff leveled map chunk
	function visible takes real ox, real oy, real tx, real ty, real samples returns boolean

	   local real highestx = ox
	   local real highesty = oy

	   local real currentx 
	   local real currenty 
	   
	   local real angle =  Atan2(ty - oy, tx - ox)
	   local real max_range = SquareRoot((tx-ox)*(tx-ox)+(ty-oy)*(ty-oy))

	   local real polar_displacement_x = (max_range/samples) * Cos(angle)
	   local real polar_displacement_y = (max_range/samples) * Sin(angle)
	   
	   local integer origin_cliff_level = GetTerrainCliffLevel(ox,oy)

	   local real i = 1.0
	   loop
		   exitwhen i>samples
		   set currentx = ox + polar_displacement_x * i
		   set currenty = oy + polar_displacement_y * i
		  
		   if(GetTerrainCliffLevel(currentx,currenty) >  GetTerrainCliffLevel(highestx,highesty)) then
				set highestx = currentx
				set highesty = currenty
		   endif 

		   if(GetTerrainCliffLevel(currentx,currenty) <  GetTerrainCliffLevel(highestx,highesty)) then
				if( origin_cliff_level  != GetTerrainCliffLevel(highestx,highesty)) then
					 return false
				endif
		   endif
		   set i = i + 1.0
	   endloop
	   return true

	endfunction

	// returns if line from origin to target is blocked by a cliff leveled map chunk
	function visibleBJ takes location origin, location target, real numsamples returns boolean
	   return visible(GetLocationX(origin),GetLocationY(origin),GetLocationX(target),GetLocationY(target),numsamples)
	endfunction

	function GlobalWeather takes integer raintype returns nothing
		local integer A = 1
		local integer B
		local real minx = GetRectMinX(bj_mapInitialPlayableArea)
		local real maxx = GetRectMaxX(bj_mapInitialPlayableArea)
		local real miny = GetRectMinY(bj_mapInitialPlayableArea)
		local real maxy = GetRectMaxY(bj_mapInitialPlayableArea)
		local integer steps = 5
		local real dx = (maxx-minx) / steps
		local real dy = (maxy-miny) / steps
		local rect r
		loop
			exitwhen A>steps
			set B = 1
			loop
				exitwhen B>steps
				if udg_weather[A*steps+B]!=null then
					call EnableWeatherEffect( udg_weather[A*steps+B], false )
					call RemoveWeatherEffect( udg_weather[A*steps+B] )
				endif
				set r = Rect(minx+(A-1)*dx-100.,miny+(B-1)*dy-100.,minx+A*dx+100.,miny+B*dy+100.)
				set udg_weather[A*steps+B] = AddWeatherEffect( r, raintype )
				call EnableWeatherEffect(udg_weather[A*steps+B],true)
				call RemoveRect(r)
				call TriggerSleepAction(0.)
				set B=B+1
			endloop
			set A=A+1
		endloop
		set r = null
	endfunction

	function SelectPoint takes location l, real r1, real r2 returns location
		local real x = GetLocationX(l)
		local real y = GetLocationY(l)
		local real r = GetRandomReal(r1,r2)
		local real theta = GetRandomReal(0,6.28)
		local real ux = Clamp(x+r*Cos(theta),GetRectMinX(bj_mapInitialPlayableArea),GetRectMaxX(bj_mapInitialPlayableArea))
		local real uy = Clamp(y+r*Sin(theta),GetRectMinY(bj_mapInitialPlayableArea),GetRectMaxY(bj_mapInitialPlayableArea))
		return Location(ux,uy)
	endfunction

	function SelectPoint2 takes real x, real y, real r1, real r2 returns location
		local real r = GetRandomReal(r1,r2)
		local real theta = GetRandomReal(0,6.28)
		local real ux = Clamp(x+r*Cos(theta),GetRectMinX(bj_mapInitialPlayableArea),GetRectMaxX(bj_mapInitialPlayableArea))
		local real uy = Clamp(y+r*Sin(theta),GetRectMinY(bj_mapInitialPlayableArea),GetRectMaxY(bj_mapInitialPlayableArea))
		return Location(ux,uy)
	endfunction

	function SelectGround takes nothing returns boolean
		if IsUnitType(GetFilterUnit(),UNIT_TYPE_FLYING)==true then
			return false
		endif
		return true
	endfunction

	globals
		private group AMGetUnitsInRange_G
	endglobals
	
	function AMGetUnitsInRange takes real r, location l, boolexpr f returns group
		local group g = CreateGroup()
		call GroupEnumUnitsInRangeOfLoc(g,l,r,f)
		set AMGetUnitsInRange_G = g 
		set g = null
		return AMGetUnitsInRange_G
	endfunction

	function TargetCheck takes nothing returns boolean
		local integer i = GetUnitTypeId(GetFilterUnit())
		return i=='e00H' or i=='e00C'
	endfunction

	function SelectClassA takes nothing returns boolean
		return (GetUnitPointValue(GetFilterUnit())==50 and GetUnitTypeId(GetFilterUnit())!='n00P' and GetWidgetLife(GetFilterUnit())>0.405)
	endfunction

	
	function UnitSelected takes nothing returns boolean
		return IsUnitSelected(GetTriggerUnit(),GetFilterPlayer())
	endfunction

	function RemoveUnitAll takes nothing returns nothing
		call RemoveUnit(GetEnumUnit())
	endfunction

	function surucompare takes real c, real t, real s returns boolean
		return (s>=0 and c>=t) or (s<0 and c<=t)
	endfunction

	function SmoothUnitResize_Update takes nothing returns nothing
		local timer t = GetExpiredTimer()
		local real dsc = getReal(t,"dsc")
		local real csc = getReal(t,"csc") + dsc
		local real tsc = getReal(t,"tsc")
		local unit u = getUnit(t,"unit")
		if u==null or surucompare(csc,tsc,dsc) then
			call FlushHandleLocals(t)
			call DestroyTimer(t)
			set t = null
		else
			call putReal(t,"csc",csc)
		endif
		call SetUnitScale(u,csc,csc,csc)
	endfunction

	function SmoothUnitResize takes unit u, real cscale, real targetscale, real time returns nothing
		local timer t
		local real dt = 0.05
		if time<=0 then
			call SetUnitScale(u,cscale,cscale,cscale)
		endif
		set t = CreateTimer()
		call SetUnitScale(u,cscale,cscale,cscale)
		call putReal(t,"csc",cscale)
		call putReal(t,"tsc",targetscale)
		call putReal(t,"dsc",dt*(targetscale-cscale)/time)
		call putUnit(t,"unit",u)
		call TimerStart(t,dt,true,function SmoothUnitResize_Update)
	endfunction

	function BlackHawkWashOff takes nothing returns nothing
		local real x = GetLocationX(udg_LZPoint)
		local real y = GetLocationY(udg_LZPoint)
		local real dist = 0
		local integer i
		call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl",x,y))
		set bj_meleeNearestMineDist = x
		set bj_lastTransmissionDuration = y
		set udg_soundpath = "Abilities\\Spells\\NightElf\\Immolation\\ImmolationDecay1.wav"
		call PlaySoundPath3D.execute()
		loop
			exitwhen dist>320
			set i = 0
			loop
				exitwhen i>320
				if GetRandomInt(0,1)==1 then
					call DestroyEffect(AddSpecialEffect( "Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl", x + dist * Cos(i * bj_DEGTORAD), y + dist * Sin(i * bj_DEGTORAD) ))
				endif
				set i=i+40
			endloop
			if GetRandomInt(0,1)==1 then
				call TriggerSleepAction(0.)
			endif
			set dist=dist+40
		endloop
	endfunction
	
	function HeloShockDamage takes nothing returns nothing
		local unit u = udg_GlobalUnit[404]
		if IsUnitType(u,UNIT_TYPE_MECHANICAL)==false and GetUnitPointValue(u)!=5 then
			call SetUnitAnimation(u,"death")
			call UnitDamageTargetBJ(u,u,50.0,ATTACK_TYPE_MELEE,DAMAGE_TYPE_NORMAL)
			call UnitAddAbility(u,'A05S')
			call ShiftMoveSpeed(u,-80.0)
			call TriggerSleepAction(0)
			call ResetUnitAnimation(u)
			call PolledWait(2.5)
			call ShiftMoveSpeed(u,30.0)
			call PolledWait(2.5)
			call UnitRemoveAbility(u,'A05S')
			call ShiftMoveSpeed(u,50.0)
		endif
		set u = null
	endfunction

	function HeloShock takes unit helo returns nothing
		local location l = GetUnitLoc(helo)
		local group g = AMGetUnitsInRange(325,l,Condition(function SelectGround))
		local unit u
		loop
			set u = FirstOfGroup(g)
			exitwhen u==null
			set udg_GlobalUnit[404]=u
			if GetWidgetLife(u)>0.405 then
				call HeloShockDamage.execute()
			endif
			call GroupRemoveUnit(g,u)
		endloop
		call DestroyGroup(g)
		set g = null
		call RemoveLocation(l)
		set l = null
	endfunction

	function KiloEvac takes unit helo returns nothing
		local location l = GetUnitLoc(helo)
		local group g = AMGetUnitsInRange(325,l,Condition(function SelectGround))
		local unit u
		local item n
		local integer i=1
		loop
			set u = FirstOfGroup(g)
			exitwhen u==null
			set n = GetUnitItem(u,'I018')
			if n!=null then
				call RemoveItem(n)
				call ALICE2Text(10.0, "Kilo evacuated. |cff1e90ff10 XP|r awarded to all Marines." )
				set i=1
				loop
					exitwhen i>udg_InitialPlayers
					if GetPlayerSlotState(ConvertedPlayer(udg_Sorted[i]))!=PLAYER_SLOT_STATE_LEFT then
						set udg_Experience[udg_Sorted[i]] = udg_Experience[udg_Sorted[i]] + 10
					endif
					set i=i+1
				endloop
			endif
			call GroupRemoveUnit(g,u)
		endloop
		call DestroyGroup(g)
		set g = null
		call RemoveLocation(l)
		set l = null
		set n = null
	endfunction

	private function Infection takes unit u returns nothing
		local player p = GetOwningPlayer(u)
		local integer i = GetRandomInt(3,10)
		
		set udg_soundpath = "Abilities\\Spells\\Undead\\ReviveUndead\\ReviveUndead.wav"
		call PlaySoundPathForPlayer(p)
		
		call PolledWait(100.0*GetRandomReal(1.0,2.0))
		loop
			exitwhen 0 > i
			if u != null and GetWidgetLife(u) > 0.405 then
				call PolledWait(80.0*GetRandomReal(0.5,1.5))
			endif
			
			if u != null and GetWidgetLife(u) > 0.405 then
				call UnitRemoveAbility(u, 'BEah')
				//call SetUnitAnimation(u,"death")
				call UnitDamageTargetBJ(u,u,GetRandomReal(10.0,40.0),ATTACK_TYPE_MELEE,DAMAGE_TYPE_UNIVERSAL)
				
				// undo auto hit increase
				set udg_HitsTaken = udg_HitsTaken - 1
				set udg_PlayerHitsTaken[GetConvertedPlayerId(p)] = udg_PlayerHitsTaken[GetConvertedPlayerId(p)] - 1
				
				call UnitAddAbility(u,'A05S')
				call ShiftMoveSpeed(u,-80.0)
				call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Undead\\UndeadBlood\\UndeadBloodCryptFiend.mdl", u, "origin"))
				call TriggerSleepAction(0.1)
				call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Undead\\UndeadBlood\\UndeadBloodCryptFiend.mdl", u, "origin"))
				call ResetUnitAnimation(u)
				call PolledWait(2.5)
				call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Undead\\UndeadBlood\\UndeadBloodCryptFiend.mdl", u, "origin"))
				call ShiftMoveSpeed(u,30.0)
				call PolledWait(2.5)
				call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Undead\\UndeadBlood\\UndeadBloodCryptFiend.mdl", u, "origin"))
				call UnitRemoveAbility(u,'A05S')
				call ShiftMoveSpeed(u,50.0)
			endif
			set i = i - 1
		endloop
		
		set p = null
	endfunction
	

	private function Ailments takes nothing returns boolean
		local unit u = GetTriggerUnit()
		local unit a = GetEventDamageSource()
		local player p2 = GetOwningPlayer(u)
		local integer i 
		local integer h
		local integer n 
		local integer p 

		local boolean majorDamage = GetEventDamage() > 10.0
		
		if majorDamage then
			set n = GetUnitTypeId(a)
			set h = GetConvertedPlayerId(p2)
			set udg_HitsTaken = udg_HitsTaken + 1
			set udg_PlayerHitsTaken[h] = udg_PlayerHitsTaken[h] + 1
		endif
			
		if IsUnitType(u, UNIT_TYPE_HERO) and majorDamage and GetPlayerController(p2)==MAP_CONTROL_USER and GetUnitPointValue(u)!=98 then
			set n = GetUnitTypeId(a)
			set h = GetConvertedPlayerId(p2)
			
			if n==udg_Parasite or n=='n00D' or n=='n009' then
				set udg_TotalAilments = udg_TotalAilments + 1
				set udg_AilmentCount[1] = udg_AilmentCount[1] + 1
			endif
		endif
	
		if GetUnitTypeId(a)=='n016' and IsUnitEnemy(a,Player(0)) and IsUnitType(u, UNIT_TYPE_HERO)  then //Invisible Worm
			if GetWidgetLife(a)>0.405 then
				call KillUnit(a)
			endif
			set udg_TotalAilments = udg_TotalAilments + 1
			set udg_AilmentCount[8] = udg_AilmentCount[8] + 1
			call Infection.execute(u)
		elseif GetRandomInt(1,10)==1 and IsUnitEnemy(a,Player(0)) and majorDamage then
			call IssueImmediateOrder(a,"berserk")
			set p = 7*GetPlayerId(GetOwningPlayer(u))
			if p>42 then
				set p = 0
			endif
			
			set i = 2
			loop
				exitwhen i>7
				if GetRandomInt(1,udg_AilmentChance[p+i])==1 or (i==5 and GetUnitTypeId(a)=='U00M') then
					if IsUnitType(u,UNIT_TYPE_HERO)==true then
						set udg_TotalAilments = udg_TotalAilments + 1
						set udg_AilmentCount[i] = udg_AilmentCount[i] + 1
					endif
					set a = CreateUnit(Player(14),'n00O',GetUnitX(u),GetUnitY(u),0.0)
					call UnitAddAbility(a,udg_Ailment[i])
					if not(i==7 and GetUnitPointValue(u)==98) then
						call IssueTargetOrder(a,udg_AilmentOrder[i],u)
					endif
					call UnitApplyTimedLife(a,'Bhwd',5.0)
					exitwhen 1==1
				endif
				set i=i+1
			endloop
		endif
		set a = null
		set u = null
		set p2= null
		return false
	endfunction

	function RegisterUnitForAilmentChecks takes unit u returns nothing
		call TriggerRegisterUnitEvent(Ailemnts_Trigger, u, EVENT_UNIT_DAMAGED)
	endfunction

	function DisableAilmentChecks takes nothing returns nothing
		call DisableTrigger(Ailemnts_Trigger)
	endfunction

	
	function PlatoonReinforcements takes nothing returns nothing
		local real handicap = 0.0
		local integer i = 1
		local integer id = 0
		local integer LZSelect = GetRandomInt(1,8)
		local real x = GetRectCenterX(udg_LandingZones[LZSelect])
		local real y = GetRectCenterY(udg_LandingZones[LZSelect])
		local location l
		local real angle
		local boolean present = false
		local unit u
		local real theta = GetRandomReal(0.0,6.28)
		local real ux = Clamp(x+3000.0*Cos(theta),GetRectMinX(bj_mapInitialPlayableArea),GetRectMaxX(bj_mapInitialPlayableArea))
		local real uy = Clamp(y+3000.0*Sin(theta),GetRectMinY(bj_mapInitialPlayableArea),GetRectMaxY(bj_mapInitialPlayableArea))
		local unit blackhawk
		if udg_InitialPlayers==udg_Players then
			return
		else
			loop
				exitwhen i>udg_InitialPlayers
				if (GetWidgetLife(udg_Hero[udg_Sorted[i]])<=0.405 or udg_Experience[udg_Sorted[i]]>400000) and GetPlayerSlotState(ConvertedPlayer(udg_Sorted[i]))!=PLAYER_SLOT_STATE_LEFT then
					set id=1337
				endif
				set i=i+1
			endloop
			set i=1
			if id!=1337 then
				return
			endif
		endif
		set l = Location(x,y)
		set udg_LZPoint = Location(x,y)
		set blackhawk = CreateUnit(Player(11),'h009',ux,uy,theta+3.14)
		call UnitApplyTimedLife(blackhawk,'Bhwd',90.0)
		call SetUnitScalePercent(blackhawk,50.0,50.0,50.0)
		
		call RemoveGuardPosition(blackhawk)
		call TriggerSleepAction(0.)
		call IssuePointOrder(blackhawk,"move",x,y)
		call StartSound(gg_snd_BlackHawkRotor)
		call PolledWait(5.5)
		call SetUnitFlyHeight(blackhawk,15.0,130.0)
		call SmoothUnitResize(blackhawk,1.45,1.55,4)
		call SetLandingAreaWindEnabled (true)
		call PolledWait(3.)
		call SetUnitTimeScalePercent(blackhawk,65.0)
		call BlackHawkWashOff.execute()
		call HeloShock(blackhawk)
		call AttachSoundToUnit(gg_snd_BlackHawkLand,blackhawk)
		call SetSoundVolume(gg_snd_BlackHawkLand,127)
		call StartSound(gg_snd_BlackHawkLand)
		call PolledWait(2.5)
		call KiloEvac(blackhawk)
		call IssueImmediateOrder(blackhawk,"holdposition")
		loop
			exitwhen i>udg_InitialPlayers
			set angle = 360.0*(I2R(i)-1)/I2R(udg_InitialPlayers)
			if (GetWidgetLife(udg_Hero[udg_Sorted[i]])<=0.405 or udg_Experience[udg_Sorted[i]]>400000) and GetPlayerSlotState(ConvertedPlayer(udg_Sorted[i]))!=PLAYER_SLOT_STATE_LEFT then
				set present = true
				set handicap = handicap + 0.015
				if GetRandomInt(0,10)==1 and udg_Experience[udg_Sorted[i]]>60000 then
					set id = 'z00E' //IUL
				elseif udg_Chapter!=1 and GetRandomInt(0,55)==1 and udg_Experience[udg_Sorted[i]]>60000 then
					set id = 'z006' //Pilot
				elseif GetRandomInt(0,12)==1 and udg_Experience[udg_Sorted[i]]>30000 then
					set id = 'z00G' //Sniper
				elseif GetRandomInt(0,6)==1 then
					set id = 'z009' //Flamethrower
				elseif GetRandomInt(0,6)==1 then
					set id = 'z001' //Corpsman
				elseif GetRandomInt(0,8)==1 then
					set id = 'z004' //Engineer
				elseif GetRandomInt(0,3)==1 then
					set id = 'z000' //Machine Gunner
				elseif GetRandomInt(0,5)==1 then
					set id = 'z00F' //Marksman
				else
					set id = 'z008' //Rifleman
				endif
				set u = CreateUnit(ConvertedPlayer(udg_Sorted[i]),id,x+80.0,y-175.0,0.0)
		   
				call UnitAddItemById(u,'I004') //Medkit
				if id=='z001' then
					//call TriggerRegisterUnitEvent(gg_trg_Anti_Venom,u,EVENT_UNIT_SPELL_EFFECT)
				elseif id=='z006' then
					//call TriggerRegisterUnitEvent(gg_trg_Control_Aircraft,u,EVENT_UNIT_SPELL_EFFECT)
				elseif id=='z004' then
					call UnitAddItemById(u,'I014') //Field Lights
					//call TriggerRegisterUnitEvent(gg_trg_Nanosteel_Net,u,EVENT_UNIT_SPELL_EFFECT)
				endif
				call UnitAddAbility(u,'A04R') //NVG
				call RegisterUnitForAilmentChecks(u)
				
				//call TriggerRegisterUnitEvent(gg_trg_Article_15,u,EVENT_UNIT_DEATH)
				call IssuePointOrder(u,"attack", x + (325.0*Cos(angle*0.01745)), y + (325.0*Sin(angle*0.01745)) )
			endif
			call TriggerSleepAction(0.)
			set i=i+1
		endloop
		if present then
			set udg_soundpath = "war3mapImported\\LockAndLoad.wav"
			call PlaySoundPath.execute()
			//call StartSound(gg_snd_RockandRoll)
		endif
		if present then
			call SetCameraQuickPosition(x,y)
			call PingMinimapEx(x,y,15.0,255,0,0,false)
			call ALICEText(15.0, "|cfff3ad00ALICE|r : Reinforcements have arrived." )
			call SetPlayerHandicap(Player(13),GetPlayerHandicap(Player(13))+handicap)
			call SetPlayerHandicap(Player(14),GetPlayerHandicap(Player(14))+handicap)
		endif
		set i=1
		loop
			exitwhen i>12
			call PolledWait(5.)
			call KiloEvac(blackhawk)
			set i=i+1
		endloop
		call BlackHawkWashOff.execute()
		call SetUnitFlyHeight(blackhawk,500.0,200.0)
		call SmoothUnitResize(blackhawk,1.55,1.45,3)
		call SetUnitTimeScalePercent(blackhawk,100.0)
		
		call IssuePointOrder(blackhawk,"move",13000.0,10000.0)
		call PolledWait(3.5)
		call SetLandingAreaWindEnabled (false)
		call EnumDestructablesInCircleBJ(600,l,function TreeShakeEnd)
		call PolledWait(3.)
		call RemoveUnit(blackhawk)
		call RemoveLocation(l)
		call RemoveLocation(udg_LZPoint)
		set l = null
		set u = null
		set blackhawk = null
	endfunction

	function LightningAmbience takes nothing returns nothing
		local integer i = 1
		local real x = GetRandomReal( GetRectMinX(bj_mapInitialPlayableArea), GetRectMaxX(bj_mapInitialPlayableArea) )
		local real y = GetRandomReal( GetRectMinY(bj_mapInitialPlayableArea), GetRectMaxY(bj_mapInitialPlayableArea) )
		//local ubersplat ub
		if GetRandomInt(1,5)==1 and udg_Lighting==false then
			set udg_Lighting = true
			call DestroyEffect(AddSpecialEffect( "Doodads\\Cinematic\\Lightningbolt\\Lightningbolt", x, y ))
			loop
				exitwhen i > udg_InitialPlayers
				if ConvertedPlayer(udg_Sorted[i])==GetLocalPlayer() then
					if udg_NightVision[udg_Sorted[i]]==false then
						call CinematicFilterGenericBJ( 0.25, BLEND_MODE_BLEND, "ReplaceableTextures\\CameraMasks\\White_mask.blp", 0.0, 0.0, 0.0, 100, 100.0, 100.0, 100.0, 15.0 )
					else
						call CinematicFilterGenericBJ( 0.25, BLEND_MODE_BLEND, "ReplaceableTextures\\CameraMasks\\White_mask.blp", 0.0, 100.0, 0.0, 10.0, 100.0, 100.0, 100.0, 15.0 )
					endif
				endif
				set i = i + 1
			endloop
			set i = 1
			call StartSound(gg_snd_Ambience1)
			
			call PolledWait(0.5)
			loop
				exitwhen i > udg_InitialPlayers
				if ConvertedPlayer(udg_Sorted[i])==GetLocalPlayer() then
					if udg_NightVision[udg_Sorted[i]]==false then
						call CinematicFilterGenericBJ( 0.0, BLEND_MODE_MODULATE_2X, "ReplaceableTextures\\CameraMasks\\White_mask.blp", 100.0, 100.0, 100.0, 5.0, 0.0, 0.0, 0.0, 100.0 )
						call CinematicFilterGenericBJ( 1.0, BLEND_MODE_BLEND, "ReplaceableTextures\\CameraMasks\\Black_mask.blp", 20.0, 20.0, 20.0, 0.00, 20.0, 20.0, 20.0, udg_Visibility )
					else
						call CinematicFilterGenericBJ( 1.0, BLEND_MODE_MODULATE_2X, "ReplaceableTextures\\CameraMasks\\White_mask.blp", 100.0, 100.0, 100.0, 100.0, 0.0, 100.0, 0, 10.0 )
					endif
				endif
				set i = i + 1
			endloop
			
			call DestroyEffect(AddSpecialEffect( "Effect_GreatLightning.mdl", x, y ))	
			call UnitDamagePoint( udg_Residence41, 0, 100.0, x, y, 200.00, true, false, ATTACK_TYPE_SIEGE, DAMAGE_TYPE_DEMOLITION, WEAPON_TYPE_WHOKNOWS )
			
			//set ub = CreateUbersplat(x,y,"DHLB",255,255,255,255,false,false)
			//call SetUbersplatRenderAlways(ub,true)
			//call ShowUbersplat(ub,true)
			
			call PolledWait(1.)
			set udg_Lighting = false
			call IntermissionRestore()
		endif
		//set ub = null
	endfunction

	private function LandingAreaWindCB takes nothing returns nothing
		local real x = GetLocationX(udg_LZPoint)
		local real y = GetLocationY(udg_LZPoint)
		local rect r = Rect(x-350,y-350,x+350,y+350)
		call EnumDestructablesInRect(r,null,function TreeShake)
		call RemoveRect(r)
		set r = null
	endfunction


	globals
		private rect arty_rect
	endglobals
	private function singleArtyShell takes unit source, real x, real y, real damage, string eff returns nothing
		local real explosion_damage_radius = 300.0
		
		call SetRect(arty_rect, x-explosion_damage_radius,y-explosion_damage_radius,x+explosion_damage_radius,y+explosion_damage_radius)
		
		call DamageTrees(arty_rect,R2I(damage))
		call EnumItemsInRect(arty_rect,Condition(function killItemFast), null)
		call GroupEnumUnitsInRect(G, arty_rect, Condition(function killexplosiveFast ))
		
		// create effects
		call DestroyEffect( AddSpecialEffect(eff, x,y))
		call DestroyEffect( AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl",  x,y ))
		
		// damage area
		call DamageAreaExplosion(source,x,y,R2I(damage),explosion_damage_radius)
	endfunction

	// drops shells and damage per shell
	private function executeArtySequence takes unit source, real x, real y, integer howmany,real damage, real radius, real time, integer typ returns nothing
		 
		local integer i = 0
		local real barrage_delay = 1.5/(I2R(howmany))
		local real d = GetRandomDirectionDeg()
		local real x2
		local real y2
		local real randomdist 

		call PolledWait(time)

		if udg_Intermission then 
			call PolledWait(9.0)
		endif

		loop
			exitwhen i > howmany-1
			if(R2I(ModuloReal(I2R(i),2.00))==0) then
				set d = GetRandomDirectionDeg()
			else
				set d = d - 180.00
			endif 

			set  randomdist = GetRandomReal(50, radius +50.0)
			set x2 = x + randomdist * Cos(d * bj_DEGTORAD)
			set y2 = y + randomdist * Sin(d * bj_DEGTORAD)

			if typ == 1 then
				call singleArtyShell(source, x2, y2, damage, "Effect_Artillery.mdx" )
			else
				call singleArtyShell(source, x2, y2, damage, "")
			endif

			call TriggerSleepAction(barrage_delay)
			set i = i + 1
		 endloop
	endfunction
	
	function ArtHandler takes unit caster, real x, real y, integer n, real damage, real dp, real time, integer typ returns nothing
		call executeArtySequence.execute(caster, x , y, n, damage,dp, time, typ)
	endfunction
	
	
	function RandomSpawn2 takes integer utype, integer nunits, integer ntimes returns nothing
		local integer i = 1
		local integer i2 = 1
		local integer spawn = GetRandomInt(1,4)
		local real x
		local real y
		local unit u
		loop
			exitwhen i>ntimes
			set x = GetRandomReal(GetRectMinX(udg_UndeadRandomSpawn[spawn]),GetRectMaxX(udg_UndeadRandomSpawn[spawn]))
			set y = GetRandomReal(GetRectMinY(udg_UndeadRandomSpawn[spawn]),GetRectMaxY(udg_UndeadRandomSpawn[spawn]))
			loop
				exitwhen i2>nunits
				call TriggerSleepAction(0.)
				set u = CreateUnit(Player(9),utype,x,y,0.0)
				call SetLoadState(I2S(GetHandleId(u)),1)
				set i2=i2+1
			endloop
			set i=i+1
		endloop  
		set u = null
	endfunction

	private function init takes nothing returns nothing
		set Ailemnts_Trigger = CreateTrigger()
		call TriggerAddCondition(Ailemnts_Trigger,Condition (function Ailments))
		
		set LandingAreaWind = CreateTrigger()
		call DisableTrigger(LandingAreaWind)
		call TriggerRegisterTimerEvent(LandingAreaWind,0.75,true)
		call TriggerAddAction(LandingAreaWind,function LandingAreaWindCB)
		
		set arty_rect = Rect(0,0,1,1)
		
		set ItemRemovalTrigger = CreateTrigger()
		call TriggerAddAction(ItemRemovalTrigger,function ItemRemovalEngine)
	endfunction


endlibrary

